﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.Remoting.Messaging;

namespace Shumisen.Core.Composition.Aop
{
	public class InterceptorChain : IInterceptor
	{
		private readonly ReadOnlyCollection<IInterceptor> _interceptors;

		public InterceptorChain(IEnumerable<IInterceptor> interceptors)
		{
			Guard.ArgumentNotNull(interceptors, "interceptors");
			_interceptors = interceptors.ToReadOnlyCollection();
		}

		public void Intercept(IInvocation invocation)
		{
			using (var enumerator = _interceptors.GetEnumerator())
			{
				var invocationWrapper = new InvocationWrapper(invocation, enumerator);
				invocationWrapper.Proceed();
			}
		}

		internal class InvocationWrapper : IInvocation
		{
			private readonly IInvocation _invocation;

			private readonly IEnumerator<IInterceptor> _interceptors;

			public InvocationWrapper(IInvocation invocation, IEnumerator<IInterceptor> interceptors)
			{
				Guard.ArgumentNotNull(invocation, "invocation");
				Guard.ArgumentNotNull(interceptors, "interceptors");
				_invocation = invocation;
				_interceptors = interceptors;
			}

			public Type TargetType
			{
				get
				{
					return _invocation.TargetType;
				}
			}

			public object TargetInstance
			{
				get
				{
					return _invocation.TargetInstance;
				}
			}

			public IMethodCallMessage MethodCallMessage
			{
				get
				{
					return _invocation.MethodCallMessage;
				}
			}

			public IMethodReturnMessage MethodReturnMessage
			{
				get
				{
					return _invocation.MethodReturnMessage;
				}
			}

			public void Proceed()
			{
				if (_interceptors.MoveNext())
				{
					_interceptors.Current.Intercept(this);
				} else
				{
					_invocation.Proceed();
				}
			}
		}
	}
}